Create continuous scroll view#40
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis PR adds a continuous horizontal-scroll verse view mode to the interlinearizer, complete with optimistic UI settings, refactored component architecture, and comprehensive test coverage. It splits the monolithic web view into composable layers: data hooks for tokenization and settings, atomic token/phrase components, segment rendering with display mode switching, a complex ContinuousView with smooth navigation and programmatic jumps, and a loader component orchestrating the stack. ChangesContinuous Scroll Feature & Component Refactor
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…rrows, boundary/fade behavior)
alex-rawlings-yyc
left a comment
There was a problem hiding this comment.
Added a couple of layout ideas and some incredibly minor nitpicks.
❓ Do we want to put the components in their own folder within __tests__ to mirror the structure within src?
@alex-rawlings-yyc reviewed 15 files and all commit messages, and made 6 comments.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on imnasnainaec).
src/interlinearizer.web-view.tsx line 130 at r1 (raw file):
)} {!bookError && !tokenizeError && !isLoading && book && continuousScroll === true && (
⛏️ continuousScroll === true can be simplified to continuousScroll
src/interlinearizer.web-view.tsx line 131 at r1 (raw file):
{!bookError && !tokenizeError && !isLoading && book && continuousScroll === true && ( <ContinuousView
❓ Would be best for the continuous view to be static and have only the segment view scroll.
src/interlinearizer.web-view.tsx line 151 at r1 (raw file):
segment={seg} isActive={seg.startRef.verse === scrRef.verseNum} displayMode={continuousScroll === true ? 'baseline-text' : 'token-chip'}
⛏️ continuousScroll === true can be simplified to continuousScroll
src/interlinearizer.web-view.tsx line 226 at r1 (raw file):
/> } endAreaChildren={
❓ Might it be better to move the toggle here to reduce the number of toolbars?
src/components/ContinuousView.tsx line 124 at r1 (raw file):
const focusedSeg = tokenSegmentRef.current[currentlyFocusedPhrase.tokenIndex]; if ( focusedSeg &&
⛏️ this could use optional chaining
- Create useInterlinearizerBookData hook to consolidate USJ fetch, tokenization, and state - Remove ProjectBookFetcher component entirely - Simplify root rendering to directly use hook output - Move ContinuousView into toolbar sticky container to prevent overlap - Remove ResizeObserver and stickyTopOffset complexity - Clean up jest.setup.ts mock (no longer needed)
imnasnainaec
left a comment
There was a problem hiding this comment.
Test subfolders added.
@imnasnainaec made 3 comments and resolved 3 discussions.
Reviewable status: 9 of 18 files reviewed, 2 unresolved discussions (waiting on alex-rawlings-yyc and imnasnainaec).
src/interlinearizer.web-view.tsx line 131 at r1 (raw file):
Previously, alex-rawlings-yyc (Alex Rawlings) wrote…
❓ Would be best for the continuous view to be static and have only the segment view scroll.
Indeed. To do this smoothly, I'm replacing the ProjectBookFetcher with a custom hook.
src/interlinearizer.web-view.tsx line 226 at r1 (raw file):
Previously, alex-rawlings-yyc (Alex Rawlings) wrote…
❓ Might it be better to move the toggle here to reduce the number of toolbars?
Done, and moved the Scroll group selector over with the BookChapterControl.
alex-rawlings-yyc
left a comment
There was a problem hiding this comment.
Made a couple tweaks that should improve performance: #42
The current fade-in behaviour could be kept as an accessibility option, as I could see the words quickly scrolling by having ill effects on the photosensitive. Or perhaps the scrolling is headache-inducing for the general public, as well.
@alex-rawlings-yyc partially reviewed 9 files and all commit messages, made 2 comments, and resolved 2 discussions.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on imnasnainaec).
src/interlinearizer.web-view.tsx line 55 at r2 (raw file):
// Drive UI from optimistic local state and clear pending once the setting confirms. useEffect(() => {
The setting never seems to resolve for me, so the toggle ends up being disabled after the continuous view appears.
alex-rawlings-yyc
left a comment
There was a problem hiding this comment.
@alex-rawlings-yyc made 6 comments.
Reviewable status: all files reviewed, 7 unresolved discussions (waiting on imnasnainaec).
src/interlinearizer.web-view.tsx line 117 at r2 (raw file):
/> {projectId && !bookError && !tokenizeError && !isLoading && book && continuousScroll && ( <div className="tw-bg-background tw-py-2">
⛏️ Might be nice to have a line or shadow on the bottom for clear separation
src/interlinearizer.web-view.tsx line 118 at r2 (raw file):
{projectId && !bookError && !tokenizeError && !isLoading && book && continuousScroll && ( <div className="tw-bg-background tw-py-2"> <ContinuousView
❓ It may be worthwhile to make the scrollbar only appear with the segment view so we can implement scrolling controls in the continuous view (e.g., scrolling down moves the view forward). Though this may involve decoupling the x-position of the view from the focused token, so perhaps not. I just found myself wanting to use the scroll wheel to navigate the continuous view.
src/interlinearizer.web-view.tsx line 174 at r2 (raw file):
isActive={seg.startRef.verse === scrRef.verseNum} displayMode={continuousScroll ? 'baseline-text' : 'token-chip'} onClick={() =>
If this component is memoized, this function should be wrapped in useCallback() and the onClick signature in SegmentView changed, e.g.
interlinearizer.web-view.tsx
const handleSegmentSelect = useCallback(
(ref: { book: string; chapter: number; verse: number }) => {
setScrRef({ book: ref.book, chapterNum: ref.chapter, verseNum: ref.verse });
},
[setScrRef],
);SegmentView.tsx
onClick?: (ref: { book: string; chapter: number; verse: number }) => void;src/components/PhraseBox.tsx line 13 at r2 (raw file):
* @returns A bordered inline container */ export default function PhraseBox({
I think it would be good to wrap this in memo() to reduce the amount of re-renders given how many of these there can be at once and how infrequently they're changed
src/components/SegmentView.tsx line 18 at r2 (raw file):
* @returns A button containing the segment's verse label and content */ export default function SegmentView({
I think it would be good to wrap this in memo() to reduce the amount of re-renders given how many of these there can be at once and how infrequently they're changed
src/components/TokenChip.tsx line 11 at r2 (raw file):
* @returns A styled inline span */ export default function TokenChip({ token }: Readonly<{ token: Token }>) {
I think it would be good to wrap this in memo() to reduce the amount of re-renders given how many of these there can be at once and how infrequently they're changed
imnasnainaec
left a comment
There was a problem hiding this comment.
@imnasnainaec made 2 comments and resolved 6 discussions.
Reviewable status: 4 of 26 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc and imnasnainaec).
src/interlinearizer.web-view.tsx line 55 at r2 (raw file):
Previously, alex-rawlings-yyc (Alex Rawlings) wrote…
The setting never seems to resolve for me, so the toggle ends up being disabled after the continuous view appears.
Fixed.
src/interlinearizer.web-view.tsx line 118 at r2 (raw file):
Previously, alex-rawlings-yyc (Alex Rawlings) wrote…
❓ It may be worthwhile to make the scrollbar only appear with the segment view so we can implement scrolling controls in the continuous view (e.g., scrolling down moves the view forward). Though this may involve decoupling the x-position of the view from the focused token, so perhaps not. I just found myself wanting to use the scroll wheel to navigate the continuous view.
I think that will be a follow-up task.
|
@alex-rawlings-yyc Addressing your and Devin's feedback and adding comprehensive tests to the new material resulted in an extreme refactor. Please take a look at the new structure and let me know what you think. I'll wait for the next round of comments from CodeRabbit and Devin before I take it out of draft (hopefully tomorrow morning), so don't feel like you have to do a careful review quite yet. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/hooks/useInterlinearizerBookData.ts (1)
44-61: 💤 Low valueConsider extracting duplicate writing system fallback logic.
The fallback logic
isPlatformError(writingSystem) ? 'und' : writingSystem || 'und'is duplicated at lines 45 and 55. While minor, extracting this to a shared variable or helper would improve maintainability.♻️ Suggested refactor
+ const resolvedWritingSystem = useMemo( + () => (isPlatformError(writingSystem) ? 'und' : writingSystem || 'und'), + [writingSystem], + ); + const [book, tokenizeError] = useMemo((): [ Book | undefined, { message: string; raw: unknown } | undefined, ] => { if (!bookResult || isPlatformError(bookResult)) return [undefined, undefined]; try { - const ws = isPlatformError(writingSystem) ? 'und' : writingSystem || 'und'; - return [tokenizeBook(extractBookFromUsj(bookResult, ws)), undefined]; + return [tokenizeBook(extractBookFromUsj(bookResult, resolvedWritingSystem)), undefined]; } catch (err) { return [undefined, { message: err instanceof Error ? err.message : String(err), raw: err }]; } - }, [bookResult, writingSystem]); + }, [bookResult, resolvedWritingSystem]); useEffect(() => { if (!tokenizeError) return; - const ws = isPlatformError(writingSystem) ? 'und' : writingSystem || 'und'; logger.error('Failed to parse/tokenize USJ book', tokenizeError.raw, { message: tokenizeError.message, - writingSystem: ws, + writingSystem: resolvedWritingSystem, projectId, book: scrRef.book, }); - }, [tokenizeError, writingSystem, projectId, scrRef.book]); + }, [tokenizeError, resolvedWritingSystem, projectId, scrRef.book]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useInterlinearizerBookData.ts` around lines 44 - 61, Extract the duplicated writing-system fallback expression into a single variable or small helper and use it in both places; locate the duplicate conditional using isPlatformError(writingSystem) ? 'und' : writingSystem || 'und' inside the hook (used around tokenizeBook/extractBookFromUsj and in the logger.error call) and replace both occurrences with a single const (e.g., ws or getFallbackWritingSystem(writingSystem)) defined once at the top of the hook or just before the try/useEffect so tokenizeBook, extractBookFromUsj, and logger.error all reference the same value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/hooks/useInterlinearizerBookData.ts`:
- Around line 44-61: Extract the duplicated writing-system fallback expression
into a single variable or small helper and use it in both places; locate the
duplicate conditional using isPlatformError(writingSystem) ? 'und' :
writingSystem || 'und' inside the hook (used around
tokenizeBook/extractBookFromUsj and in the logger.error call) and replace both
occurrences with a single const (e.g., ws or
getFallbackWritingSystem(writingSystem)) defined once at the top of the hook or
just before the try/useEffect so tokenizeBook, extractBookFromUsj, and
logger.error all reference the same value.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bd7ffb76-316d-4753-9709-548761944a5b
📒 Files selected for processing (21)
src/__tests__/components/ContinuousScrollToggle.test.tsxsrc/__tests__/components/ContinuousView.test.tsxsrc/__tests__/components/Interlinearizer.test.tsxsrc/__tests__/components/InterlinearizerLoader.test.tsxsrc/__tests__/components/PhraseBox.test.tsxsrc/__tests__/components/ScriptureNavControls.test.tsxsrc/__tests__/components/SegmentView.test.tsxsrc/__tests__/hooks/useInterlinearizerBookData.test.tssrc/__tests__/hooks/useOptimisticBooleanSetting.test.tssrc/__tests__/interlinearizer.web-view.test.tsxsrc/components/ContinuousScrollToggle.tsxsrc/components/ContinuousView.tsxsrc/components/Interlinearizer.tsxsrc/components/InterlinearizerLoader.tsxsrc/components/PhraseBox.tsxsrc/components/ScriptureNavControls.tsxsrc/components/SegmentView.tsxsrc/components/TokenChip.tsxsrc/hooks/useInterlinearizerBookData.tssrc/hooks/useOptimisticBooleanSetting.tssrc/interlinearizer.web-view.tsx
✅ Files skipped from review due to trivial changes (2)
- src/tests/components/SegmentView.test.tsx
- src/components/InterlinearizerLoader.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/SegmentView.tsx
- src/components/TokenChip.tsx
Resolves #38
Resolves #39
Authored locally with Copilot.
Devin: https://app.devin.ai/review/sillsdev/interlinearizer-extension/pull/40
This change is
Summary by CodeRabbit
Release Notes
New Features
Documentation